package com.xuecheng.content.service.impl;

import cn.hutool.json.JSONUtil;
import com.xuecheng.base.exception.BusinessException;
import com.xuecheng.base.exception.CommonError;
import com.xuecheng.base.utils.JsonUtil;
import com.xuecheng.content.config.MultipartSupportConfig;
import com.xuecheng.content.feignclient.MediaServiceClient;
import com.xuecheng.content.mapper.CourseCategoryMapper;
import com.xuecheng.content.model.dto.CourseBaseInfoDto;
import com.xuecheng.content.model.dto.CoursePreviewDto;
import com.xuecheng.content.model.dto.TeachplanDto;
import com.xuecheng.content.model.po.*;
import com.xuecheng.content.mapper.CoursePublishMapper;
import com.xuecheng.content.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CoursePublishServiceImpl extends ServiceImpl<CoursePublishMapper, CoursePublish> implements CoursePublishService {

    @Autowired
    private CourseBaseService courseBaseService;

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CourseTeacherService courseTeacherService;

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private CoursePublishPreService coursePublishPreService;

    @Resource
    private MqMessageService mqMessageService;

    @Resource
    private MediaServiceClient mediaServiceClient;

    /**
     * byId获取课程预览信息
     *
     * @param courseId 课程id
     * @return
     */
    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {
        if (courseId == null || courseId <= 0) {
            BusinessException.cast(CommonError.PARAMS_ERROR);
        }
        //得到课程基本信息,营销信息
        CourseBaseInfoDto courseBaseInfoById = courseBaseService.getCourseBaseInfoById(courseId);
        if (courseBaseInfoById == null) {
            BusinessException.cast(CommonError.QUERY_NULL);
        }
        //得到课程章节信息
        List<TeachplanDto> teachPlan = teachplanService.getTeachPlan(courseId);
        if (teachPlan == null) {
            BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
        //获取课程师资信息
        List<CourseTeacher> teachers = courseTeacherService.getTeacherListByCourseId(courseId);
        if (teachers == null) {
            BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        coursePreviewDto.setCourseBase(courseBaseInfoById);
        coursePreviewDto.setTeachplans(teachPlan);
        coursePreviewDto.setTeachers(teachers);
        return coursePreviewDto;
    }

    /**
     * 提交审核
     *
     * @param courseId
     */
    private static final String IS_SUBMITED = "202003";

    /**
     * 课程审核
     * @param companyId
     * @param courseId
     */
    @Transactional
    @Override
    public void commitAudit(Long companyId, Long courseId) {
        //======================================提交审核前进行基本校验===========================================
        //获取当前课程信息
        CourseBaseInfoDto courseBase = courseBaseService.getCourseBaseInfoById(courseId);
        // TODO 校验一下是否是该机构自己的课程
        if (courseBase == null) {
            BusinessException.cast(CommonError.QUERY_NULL);
        }
        //校验是否已提交
        String auditStatus = courseBase.getAuditStatus();
        if (auditStatus.equals(IS_SUBMITED)) {
            //已提交不能重复提交
            throw new BusinessException("课程已提交审核");
        }
        //校验是否有图片
        if (courseBase.getPic() == null) {
            throw new BusinessException("请上传课程图片");
        }
        //校验是否有章节
        List<TeachplanDto> teachPlan = teachplanService.getTeachPlan(courseId);
        if (teachPlan == null) {
            BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
        if (teachPlan.isEmpty()) {
            throw new BusinessException("课程必须有章节");
        }
        //======================================将课程信息到预发布表中===========================================
        //课程教师信息
        List<CourseTeacher> teachers = courseTeacherService.getTeacherListByCourseId(courseId);
        //营销信息
        CourseMarket courseMarket = courseMarketService.getById(courseId);
        //校验通过，将数据放入预发布表
        CoursePublishPre coursePublish = new CoursePublishPre();
        BeanUtils.copyProperties(courseBase, coursePublish);
        String teachersJson = JSONUtil.toJsonStr(teachers);
        String teachPlanJson = JSONUtil.toJsonStr(teachPlan);
        String courseMarketJson = JSONUtil.toJsonStr(courseMarket);
        //课程名称
        coursePublish.setName(courseBase.getName());
        //课程教师
        coursePublish.setTeachers(teachersJson);
        //课程计划
        coursePublish.setTeachplan(teachPlanJson);
        //课程营销信息
        coursePublish.setMarket(courseMarketJson);
        //提交时间
        coursePublish.setCreateDate(LocalDateTime.now());
        //更新状态
        coursePublish.setStatus(IS_SUBMITED);
        //机构id
        coursePublish.setCompanyId(companyId);
        CoursePublishPre coursePublishPreServiceById = coursePublishPreService.getById(courseId);
        if (coursePublishPreServiceById != null) {
            boolean b = coursePublishPreService.updateById(coursePublish);
            if (!b) BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
        boolean res = coursePublishPreService.save(coursePublish);
        if (!res) BusinessException.cast(CommonError.UNKOWN_ERROR);
        //======================================更新课程基本信息的状态===========================================
        CourseBase courseBaseServiceById = courseBaseService.getById(courseId);
        courseBaseServiceById.setAuditStatus(IS_SUBMITED);
        boolean updateById = courseBaseService.updateById(courseBaseServiceById);
        if (!updateById) BusinessException.cast(CommonError.UNKOWN_ERROR);
    }

    /**
     * 审核状态:通过
     */
    private static final String STATUS_PASS = "202004";

    /**
     * 发布状态：已发布
     */
    private static final String IS_PUBLISH = "203002";

    /**
     * 课程发布
     *
     * @param courseId
     */
    @Transactional
    @Override
    public void coursePublish(Long courseId) {
        //===================================查询课程预发布表===================================
        CoursePublishPre coursePublishPre = coursePublishPreService.getById(courseId);
        if (coursePublishPre == null) {
            throw new BusinessException("课程未提交审核");
        }
        //校验审核状态是否通过
        String status = coursePublishPre.getStatus();
        if (!status.equals(STATUS_PASS)) {
            //status不是审核为通过
            throw new BusinessException("审核通过才可发布课程！");
        }
        //===================================发布课程===================================
        CoursePublish coursePublishById = getById(courseId);
        //判断是否已发布
        if (coursePublishById != null) {
            //修改记录
            BeanUtils.copyProperties(coursePublishPre, coursePublishById);
            boolean b = updateById(coursePublishById);
            if (!b) BusinessException.cast(CommonError.UNKOWN_ERROR);
        } else {
            //添加记录
            CoursePublish coursePublish = new CoursePublish();
            BeanUtils.copyProperties(coursePublishPre, coursePublish);
            boolean res = save(coursePublish);
            if (!res) BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
        //===================================删除预发布表该记录===================================
        boolean c = coursePublishPreService.removeById(courseId);
        if (!c) BusinessException.cast(CommonError.UNKOWN_ERROR);
        //===================================修改课程基本信息的发布状态===================================
        CourseBase courseBase = courseBaseService.getById(courseId);
        courseBase.setStatus(IS_PUBLISH);
        boolean b = courseBaseService.updateById(courseBase);
        if (!b) BusinessException.cast(CommonError.UNKOWN_ERROR);
        //===================================添加到消息表===================================
        saveCoursePublishMessage(courseId);
    }

    /**
     * 课程静态化
     * @param courseId  课程id
     * @return
     */
    @Override
    public File generateCourseHtml(Long courseId) {
        File file = null;
        try {
            //获取模板
            Configuration configuration = new Configuration(Configuration.getVersion());
            String path = this.getClass().getResource("/").getPath();
            configuration.setDirectoryForTemplateLoading(new File(path+"/templates"));
            configuration.setDefaultEncoding("UTF-8");
            Template course_template = configuration.getTemplate("course_template.ftl");
            //获取课程预览信息
            CoursePreviewDto coursePreviewInfo = getCoursePreviewInfo(courseId);
            if (coursePreviewInfo==null ) BusinessException.cast(CommonError.QUERY_NULL);
            //渲染静态页面
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("model",coursePreviewInfo);
            String htmlStr = FreeMarkerTemplateUtils.processTemplateIntoString(course_template, hashMap);
            InputStream inputStream = IOUtils.toInputStream(htmlStr, "utf-8");
            file = File.createTempFile("couresePublish",".html");
            IOUtils.copy(inputStream,new FileOutputStream(file));
        } catch (Exception e) {
            log.error("页面静态化失败");
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 静态页面上传至minio
     * @param courseId
     * @param file  静态化文件
     */
    @Override
    public void uploadCourseHtml(Long courseId, File file) {
        try {
            MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
            String upload = mediaServiceClient.upload(multipartFile, "course/"+courseId+".html");
            if ("fail".equals(upload)) {
                log.error("服务熔断，执行降级逻辑");
                throw new BusinessException("静态文件上传失败");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 添加消息到消息表
     * @param courseId
     */
    private void saveCoursePublishMessage(Long courseId) {
        MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if (mqMessage == null) {
            BusinessException.cast(CommonError.UNKOWN_ERROR);
        }
    }
}
